﻿using System;
using System.Net.NetworkInformation;
using System.Web;

namespace Altairis.IisNetDiag {
    public class PingHandler : IHttpHandler {

        public void ProcessRequest(HttpContext context) {
            context.Response.ContentType = "text/plain";
            context.Response.Cache.SetCacheability(HttpCacheability.NoCache);

            // Get parameters
            var target = context.Request.QueryString.GetValue("target", context.Request.UserHostAddress);
            var timeout = context.Request.QueryString.GetValue("timeout", 500, 10, 1000);
            var count = context.Request.QueryString.GetValue("count", 5, 1, 20);
            var ttl = context.Request.QueryString.GetValue("ttl", 120, 1, 120);
            var bytes = context.Request.QueryString.GetValue("bytes", 32, 1, 512);
            
            // Check hostname
            if (!target.IsValidHost()) {
                context.Response.Output.WriteLine("Invalid target (must be host name or IP address)");
                return;
            }

            // Display header
            context.Response.Output.WriteLine("Pinging {0} with {1} bytes of data, timeout {2} ms, TTL={3}:",
                target,     // 0
                bytes,      // 1
                timeout,    // 2
                ttl);       // 3
            context.Response.Output.WriteLine();

            // Prepare ping data
            var data = new byte[bytes];
            var r = new Random();
            r.NextBytes(data);

            // Prepare pinger
            try {
                using (var ping = new Ping()) {
                    // Init counters
                    int successCount = 0;
                    long minTime = timeout, maxTime = 0, totalTime = 0;

                    for (int i = 0; i < count; i++) {
                        context.Response.Flush();
                        // Do ping
                        var reply = ping.Send(target, timeout, data, new PingOptions { Ttl = ttl });

                        // Process results
                        if (reply.Status == IPStatus.Success) {
                            // Update counters on success
                            successCount++;
                            totalTime += reply.RoundtripTime;
                            minTime = Math.Min(minTime, reply.RoundtripTime);
                            maxTime = Math.Max(maxTime, reply.RoundtripTime);

                            // Display status
                            context.Response.Output.WriteLine("Reply from {0}: {1} bytes in {2} ms",
                                reply.Address,          // 0
                                bytes,                  // 1
                                reply.RoundtripTime);   // 2
                        }
                        else if (reply.Address != null) {
                            // Got error reply from some host
                            context.Response.Output.WriteLine("Reply from {0}: {1}",
                                reply.Address,          // 0
                                reply.Status);          // 1
                        }
                        else {
                            // Some other error
                            context.Response.Output.WriteLine("Error: {0}",
                                reply.Status);          // 0
                        }
                    }

                    // Display total statistics
                    context.Response.Output.WriteLine();
                    context.Response.Output.WriteLine("Statistics: {0} sent, {1} received, {2} lost ({3}% loss)",
                        count,                                  // 0
                        successCount,                           // 1
                        count - successCount,                   // 2
                        100 - (100f * successCount / count));   // 3
                    if (successCount > 0) {
                        context.Response.Output.WriteLine("Roundtrip time: {0} ms min, {1} ms max, {2} ms average",
                            minTime,                    // 0
                            maxTime,                    // 1
                            totalTime / successCount);  // 2
                    }

                }

            }
            catch (Exception ex) {
                context.Response.Output.WriteLine("Error: {0}",
                    ex.Message);                        // 0
            }
        }

        public bool IsReusable {
            get {
                return true;
            }
        }

    }
}
